﻿using ConsoleApp.Infrastructure.Quartz;
using ConsoleApp.Job.QuartzJob;
using ConsoleApp.Util;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using System;
using System.Linq;
using System.Reflection;

namespace ConsoleApp
{
    public static class SevicesExtension
    {
        public static IServiceCollection AddConsole(this IServiceCollection services, IHostEnvironment hostEnvironment)
        {
            services.AddSingleton(new AppSettingsHelper(hostEnvironment.ContentRootPath));
            return services;
        }

        public static IServiceCollection AddJob(this IServiceCollection services)
        {
            services.Register(typeof(IJob), Assembly.GetEntryAssembly(), ServiceLifetime.Singleton);
            services.AddSingleton<IJobFactory, SingletonJobFactory>()
                    .AddSingleton<ISchedulerFactory, StdSchedulerFactory>();

            services.AddSingleton(new JobSchedule(typeof(LogJob), (SimpleScheduleBuilder x) => x.WithIntervalInSeconds(1).RepeatForever(), null, true));
            return services;
        }

        public static IServiceCollection Register(this IServiceCollection services, Type serviceType, Assembly implementAssembly, ServiceLifetime serviceLifetime)
        {
            var implementTypes = implementAssembly.GetTypes();

            if (serviceType.IsGenericType)
            {
                foreach (var impl in implementTypes)
                {
                    var it = impl.FindInterfaces((type, criteria) =>
                    {
                        var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
                        return isMatch;
                    }, serviceType);
                    foreach (var i in it)
                    {
                        services.Add(new ServiceDescriptor(i, impl, serviceLifetime));
                    }
                }
            }
            else
            {
                var implements = implementAssembly.GetTypes().Where(p => p.GetInterface(serviceType.FullName) != null);
                switch (serviceLifetime)
                {
                    case ServiceLifetime.Singleton:
                        foreach (var item in implements)
                        {
                            services.AddSingleton(item);
                        }
                        break;
                    case ServiceLifetime.Scoped:
                        foreach (var item in implements)
                        {
                            services.AddScoped(item);
                        }
                        break;
                    case ServiceLifetime.Transient:
                        foreach (var item in implements)
                        {
                            services.AddTransient(item);
                        }
                        break;
                    default:
                        break;
                }
            }
            return services;
        }
    }
}
